//! # Kubernetes 健康检查
//!
//! 提供云原生的健康检查功能，包括存活性探针、就绪性探针和启动探针。
//! 支持 Kubernetes 标准的健康检查端点和优雅关闭。

use crate::error::{K8sError, K8sResult};
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::RwLock;
use tracing::{debug, error, info, warn};

/// 健康状态
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum HealthStatus {
    /// 健康
    Healthy,
    /// 不健康
    Unhealthy,
    /// 未知状态
    Unknown,
}

impl Default for HealthStatus {
    fn default() -> Self {
        Self::Unknown
    }
}

impl std::fmt::Display for HealthStatus {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            HealthStatus::Healthy => write!(f, "healthy"),
            HealthStatus::Unhealthy => write!(f, "unhealthy"),
            HealthStatus::Unknown => write!(f, "unknown"),
        }
    }
}

/// 健康检查结果
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckResult {
    /// 检查名称
    pub name: String,
    /// 健康状态
    pub status: HealthStatus,
    /// 检查消息
    pub message: Option<String>,
    /// 检查时间
    pub timestamp: chrono::DateTime<chrono::Utc>,
    /// 检查耗时（毫秒）
    pub duration_ms: u64,
    /// 附加数据
    pub details: HashMap<String, serde_json::Value>,
}

impl HealthCheckResult {
    /// 创建健康的检查结果
    pub fn healthy(name: impl Into<String>, message: Option<String>) -> Self {
        Self {
            name: name.into(),
            status: HealthStatus::Healthy,
            message,
            timestamp: chrono::Utc::now(),
            duration_ms: 0,
            details: HashMap::new(),
        }
    }

    /// 创建不健康的检查结果
    pub fn unhealthy(name: impl Into<String>, message: Option<String>) -> Self {
        Self {
            name: name.into(),
            status: HealthStatus::Unhealthy,
            message,
            timestamp: chrono::Utc::now(),
            duration_ms: 0,
            details: HashMap::new(),
        }
    }

    /// 添加详细信息
    pub fn with_detail(mut self, key: impl Into<String>, value: serde_json::Value) -> Self {
        self.details.insert(key.into(), value);
        self
    }

    /// 设置检查耗时
    pub fn with_duration(mut self, duration: Duration) -> Self {
        self.duration_ms = duration.as_millis() as u64;
        self
    }
}

/// 健康检查接口
#[async_trait]
pub trait HealthCheck: Send + Sync {
    /// 检查名称
    fn name(&self) -> &str;

    /// 执行健康检查
    async fn check(&self) -> HealthCheckResult;

    /// 检查超时时间
    fn timeout(&self) -> Duration {
        Duration::from_secs(5)
    }
}

/// 存活性探针 (Liveness Probe)
/// 
/// 用于检查应用是否还在运行。如果存活性探针失败，Kubernetes 会重启容器。
#[async_trait]
pub trait LivenessProbe: Send + Sync {
    /// 检查应用是否存活
    async fn is_alive(&self) -> bool;
    
    /// 获取存活性检查详情
    async fn liveness_check(&self) -> HealthCheckResult {
        let start = Instant::now();
        let is_alive = self.is_alive().await;
        let duration = start.elapsed();
        
        if is_alive {
            HealthCheckResult::healthy("liveness", Some("Application is alive".to_string()))
                .with_duration(duration)
        } else {
            HealthCheckResult::unhealthy("liveness", Some("Application is not alive".to_string()))
                .with_duration(duration)
        }
    }
}

/// 就绪性探针 (Readiness Probe)
/// 
/// 用于检查应用是否准备好接收请求。如果就绪性探针失败，
/// Kubernetes 会将容器从服务的端点列表中移除。
#[async_trait]
pub trait ReadinessProbe: Send + Sync {
    /// 检查应用是否就绪
    async fn is_ready(&self) -> bool;
    
    /// 获取就绪性检查详情
    async fn readiness_check(&self) -> HealthCheckResult {
        let start = Instant::now();
        let is_ready = self.is_ready().await;
        let duration = start.elapsed();
        
        if is_ready {
            HealthCheckResult::healthy("readiness", Some("Application is ready".to_string()))
                .with_duration(duration)
        } else {
            HealthCheckResult::unhealthy("readiness", Some("Application is not ready".to_string()))
                .with_duration(duration)
        }
    }
}

/// 启动探针 (Startup Probe)
/// 
/// 用于检查应用容器是否已启动。在启动探针成功之前，
/// 其他探针都会被禁用。
#[async_trait]
pub trait StartupProbe: Send + Sync {
    /// 检查应用是否已启动
    async fn is_started(&self) -> bool;
    
    /// 获取启动检查详情
    async fn startup_check(&self) -> HealthCheckResult {
        let start = Instant::now();
        let is_started = self.is_started().await;
        let duration = start.elapsed();
        
        if is_started {
            HealthCheckResult::healthy("startup", Some("Application has started".to_string()))
                .with_duration(duration)
        } else {
            HealthCheckResult::unhealthy("startup", Some("Application has not started".to_string()))
                .with_duration(duration)
        }
    }
}

/// 健康检查器配置
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HealthCheckerConfig {
    /// 健康检查端点路径
    pub health_path: String,
    /// 存活性检查端点路径
    pub liveness_path: String,
    /// 就绪性检查端点路径
    pub readiness_path: String,
    /// 启动检查端点路径
    pub startup_path: String,
    /// 检查间隔
    pub check_interval: Duration,
    /// 检查超时
    pub check_timeout: Duration,
    /// 失败阈值
    pub failure_threshold: u32,
    /// 成功阈值
    pub success_threshold: u32,
    /// 初始延迟
    pub initial_delay: Duration,
}

impl Default for HealthCheckerConfig {
    fn default() -> Self {
        Self {
            health_path: "/health".to_string(),
            liveness_path: "/health/live".to_string(),
            readiness_path: "/health/ready".to_string(),
            startup_path: "/health/startup".to_string(),
            check_interval: Duration::from_secs(10),
            check_timeout: Duration::from_secs(5),
            failure_threshold: 3,
            success_threshold: 1,
            initial_delay: Duration::from_secs(0),
        }
    }
}

/// 健康检查器状态
#[derive(Debug, Clone)]
pub struct HealthCheckerState {
    /// 应用是否已启动
    pub started: Arc<AtomicBool>,
    /// 应用是否就绪
    pub ready: Arc<AtomicBool>,
    /// 应用是否存活
    pub alive: Arc<AtomicBool>,
    /// 优雅关闭标志
    pub shutting_down: Arc<AtomicBool>,
}

impl Default for HealthCheckerState {
    fn default() -> Self {
        Self {
            started: Arc::new(AtomicBool::new(false)),
            ready: Arc::new(AtomicBool::new(false)),
            alive: Arc::new(AtomicBool::new(true)),
            shutting_down: Arc::new(AtomicBool::new(false)),
        }
    }
}

/// 主健康检查器
pub struct HealthChecker {
    config: HealthCheckerConfig,
    state: HealthCheckerState,
    custom_checks: Arc<RwLock<Vec<Arc<dyn HealthCheck>>>>,
}

impl HealthChecker {
    /// 创建新的健康检查器
    pub fn new(config: HealthCheckerConfig) -> Self {
        Self {
            config,
            state: HealthCheckerState::default(),
            custom_checks: Arc::new(RwLock::new(Vec::new())),
        }
    }

    /// 使用默认配置创建健康检查器
    pub fn default() -> Self {
        Self::new(HealthCheckerConfig::default())
    }

    /// 获取健康检查器状态
    pub fn state(&self) -> &HealthCheckerState {
        &self.state
    }

    /// 标记应用已启动
    pub fn mark_started(&self) {
        self.state.started.store(true, Ordering::SeqCst);
        info!("Application marked as started");
    }

    /// 标记应用就绪
    pub fn mark_ready(&self) {
        self.state.ready.store(true, Ordering::SeqCst);
        info!("Application marked as ready");
    }

    /// 标记应用不就绪
    pub fn mark_not_ready(&self) {
        self.state.ready.store(false, Ordering::SeqCst);
        warn!("Application marked as not ready");
    }

    /// 开始优雅关闭
    pub fn start_shutdown(&self) {
        self.state.shutting_down.store(true, Ordering::SeqCst);
        self.state.ready.store(false, Ordering::SeqCst);
        info!("Application shutdown initiated");
    }

    /// 标记应用停止
    pub fn mark_stopped(&self) {
        self.state.alive.store(false, Ordering::SeqCst);
        info!("Application marked as stopped");
    }

    /// 添加自定义健康检查
    pub async fn add_check(&self, check: Arc<dyn HealthCheck>) {
        let mut checks = self.custom_checks.write().await;
        checks.push(check);
    }

    /// 执行综合健康检查
    pub async fn check_health(&self) -> K8sResult<HashMap<String, HealthCheckResult>> {
        let mut results = HashMap::new();

        // 基础状态检查
        results.insert("startup".to_string(), self.startup_check().await);
        results.insert("liveness".to_string(), self.liveness_check().await);
        results.insert("readiness".to_string(), self.readiness_check().await);

        // 执行自定义检查
        let checks = self.custom_checks.read().await;
        for check in checks.iter() {
            let result = tokio::time::timeout(check.timeout(), check.check()).await
                .unwrap_or_else(|_| {
                    HealthCheckResult::unhealthy(
                        check.name(),
                        Some(format!("Check timeout after {:?}", check.timeout()))
                    )
                });
            results.insert(check.name().to_string(), result);
        }

        Ok(results)
    }

    /// 获取整体健康状态
    pub async fn get_overall_status(&self) -> HealthStatus {
        match self.check_health().await {
            Ok(results) => {
                let all_healthy = results.values()
                    .all(|result| result.status == HealthStatus::Healthy);
                
                if all_healthy {
                    HealthStatus::Healthy
                } else {
                    HealthStatus::Unhealthy
                }
            }
            Err(_) => HealthStatus::Unknown,
        }
    }
}

#[async_trait]
impl LivenessProbe for HealthChecker {
    async fn is_alive(&self) -> bool {
        !self.state.shutting_down.load(Ordering::SeqCst) && 
        self.state.alive.load(Ordering::SeqCst)
    }
}

#[async_trait]
impl ReadinessProbe for HealthChecker {
    async fn is_ready(&self) -> bool {
        self.state.started.load(Ordering::SeqCst) && 
        self.state.ready.load(Ordering::SeqCst) && 
        !self.state.shutting_down.load(Ordering::SeqCst)
    }
}

#[async_trait]
impl StartupProbe for HealthChecker {
    async fn is_started(&self) -> bool {
        self.state.started.load(Ordering::SeqCst)
    }
}

/// 数据库连接健康检查
pub struct DatabaseHealthCheck {
    name: String,
    // 这里可以添加数据库连接池等
}

impl DatabaseHealthCheck {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
        }
    }
}

#[async_trait]
impl HealthCheck for DatabaseHealthCheck {
    fn name(&self) -> &str {
        &self.name
    }

    async fn check(&self) -> HealthCheckResult {
        // 这里应该实现真实的数据库连接检查
        // 目前返回一个模拟的结果
        tokio::time::sleep(Duration::from_millis(10)).await;
        
        HealthCheckResult::healthy(
            &self.name,
            Some("Database connection is healthy".to_string())
        )
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(3)
    }
}

/// Redis连接健康检查
pub struct RedisHealthCheck {
    name: String,
}

impl RedisHealthCheck {
    pub fn new(name: impl Into<String>) -> Self {
        Self {
            name: name.into(),
        }
    }
}

#[async_trait]
impl HealthCheck for RedisHealthCheck {
    fn name(&self) -> &str {
        &self.name
    }

    async fn check(&self) -> HealthCheckResult {
        // 这里应该实现真实的Redis连接检查
        // 目前返回一个模拟的结果
        tokio::time::sleep(Duration::from_millis(5)).await;
        
        HealthCheckResult::healthy(
            &self.name,
            Some("Redis connection is healthy".to_string())
        )
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(2)
    }
}

/// 外部服务健康检查
pub struct ExternalServiceHealthCheck {
    name: String,
    url: String,
    client: reqwest::Client,
}

impl ExternalServiceHealthCheck {
    pub fn new(name: impl Into<String>, url: impl Into<String>) -> Self {
        Self {
            name: name.into(),
            url: url.into(),
            client: reqwest::Client::new(),
        }
    }
}

#[async_trait]
impl HealthCheck for ExternalServiceHealthCheck {
    fn name(&self) -> &str {
        &self.name
    }

    async fn check(&self) -> HealthCheckResult {
        let start = Instant::now();
        
        match self.client.get(&self.url).send().await {
            Ok(response) => {
                let duration = start.elapsed();
                if response.status().is_success() {
                    HealthCheckResult::healthy(
                        &self.name,
                        Some(format!("Service responded with status {}", response.status()))
                    ).with_duration(duration)
                } else {
                    HealthCheckResult::unhealthy(
                        &self.name,
                        Some(format!("Service responded with status {}", response.status()))
                    ).with_duration(duration)
                }
            }
            Err(e) => {
                let duration = start.elapsed();
                HealthCheckResult::unhealthy(
                    &self.name,
                    Some(format!("Failed to connect: {}", e))
                ).with_duration(duration)
            }
        }
    }

    fn timeout(&self) -> Duration {
        Duration::from_secs(10)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::sync::Arc;

    #[test]
    fn test_health_status_display() {
        assert_eq!(HealthStatus::Healthy.to_string(), "healthy");
        assert_eq!(HealthStatus::Unhealthy.to_string(), "unhealthy");
        assert_eq!(HealthStatus::Unknown.to_string(), "unknown");
    }

    #[test]
    fn test_health_check_result_creation() {
        let result = HealthCheckResult::healthy("test", Some("OK".to_string()));
        assert_eq!(result.status, HealthStatus::Healthy);
        assert_eq!(result.name, "test");
        assert_eq!(result.message, Some("OK".to_string()));
    }

    #[tokio::test]
    async fn test_health_checker_state() {
        let checker = HealthChecker::default();
        
        // 初始状态
        assert!(!checker.state.started.load(Ordering::SeqCst));
        assert!(!checker.state.ready.load(Ordering::SeqCst));
        assert!(checker.state.alive.load(Ordering::SeqCst));
        
        // 标记启动
        checker.mark_started();
        assert!(checker.state.started.load(Ordering::SeqCst));
        
        // 标记就绪
        checker.mark_ready();
        assert!(checker.state.ready.load(Ordering::SeqCst));
        
        // 开始关闭
        checker.start_shutdown();
        assert!(checker.state.shutting_down.load(Ordering::SeqCst));
        assert!(!checker.state.ready.load(Ordering::SeqCst));
    }

    #[tokio::test]
    async fn test_liveness_probe() {
        let checker = HealthChecker::default();
        
        // 应用存活
        assert!(checker.is_alive().await);
        
        // 开始关闭后不存活
        checker.start_shutdown();
        assert!(!checker.is_alive().await);
    }

    #[tokio::test]
    async fn test_readiness_probe() {
        let checker = HealthChecker::default();
        
        // 初始状态不就绪
        assert!(!checker.is_ready().await);
        
        // 标记启动和就绪
        checker.mark_started();
        checker.mark_ready();
        assert!(checker.is_ready().await);
        
        // 关闭后不就绪
        checker.start_shutdown();
        assert!(!checker.is_ready().await);
    }

    #[tokio::test]
    async fn test_startup_probe() {
        let checker = HealthChecker::default();
        
        // 初始状态未启动
        assert!(!checker.is_started().await);
        
        // 标记启动
        checker.mark_started();
        assert!(checker.is_started().await);
    }

    #[tokio::test]
    async fn test_custom_health_check() {
        let checker = HealthChecker::default();
        let db_check = Arc::new(DatabaseHealthCheck::new("database"));
        
        checker.add_check(db_check.clone()).await;
        
        let results = checker.check_health().await.unwrap();
        assert!(results.contains_key("database"));
        assert_eq!(results["database"].status, HealthStatus::Healthy);
    }

    #[tokio::test]
    async fn test_overall_health_status() {
        let checker = HealthChecker::default();
        
        // 标记应用就绪
        checker.mark_started();
        checker.mark_ready();
        
        let status = checker.get_overall_status().await;
        assert_eq!(status, HealthStatus::Healthy);
    }
}